﻿activityFeed.LikeViewModel = function (currentUser) {
    var self = this;

    this.user = ko.observable();
};

activityFeed.UpdatesMapper = function (user, removeUpdateHandler, onUpdateViewModelInitialize) {
    var self = this;

    var commentMapping =
        {
            'publisher': {
                create: function (data) { return data.data; }
            }
        };

    var likeMapping =
        {
            'user': {
                create: function (data) { return data.data; }
            }
        };

    var updateMapping = function (updateViewModel) {
        this.comments = { create: function (data) { return self.mapCommentToCommentViewModel(data.data, updateViewModel); } };
        this.likes = {
            create: function (data) {
                var like = new activityFeed.LikeViewModel(user);
                return ko.mapping.fromJS(data.data, likeMapping, like);
            }
        };

        this.publisher =
            {
                create: function (data) {
                    return data.data;
                }
            };
    };

    this.mapLikeToLikeViewModel = function (like) {
        var likeViewModel = new activityFeed.LikeViewModel(user);
        return ko.mapping.fromJS(like, likeMapping, likeViewModel);
    };

    this.mapCommentToCommentViewModel = function (comment, update) {
        var commentViewModel = new activityFeed.CommentViewModel(user, update.removeCommentHandler);
        return ko.mapping.fromJS(comment, commentMapping, commentViewModel);
    };

    this.mapUpdateToUpdateViewModel = function (update) {
        update.publishedOn = new Date(Date.parse(update.publishedOn));
        var updateViewModel = new activityFeed.UpdateViewModel(user, removeUpdateHandler, update);
        var mapping = new updateMapping(updateViewModel);
        updateViewModel = ko.mapping.fromJS(update, mapping, updateViewModel);
        if (onUpdateViewModelInitialize) {
            onUpdateViewModelInitialize(updateViewModel);
        }
        return updateViewModel;
    };

    this.mapUpdates = function (updates) {
        return $.map(updates, function (update) {
            return self.mapUpdateToUpdateViewModel(update);
        });
    };
};



activityFeed.ActivityFeedViewModel = function (options) {
    var self = this;

    var removeUpdate = function (update) {
        var promise = activityFeed.api.removeUpdate(update).then(function () {
            self.updates.remove(update);
        });
        return promise;
    };

    var updatesMapper = new activityFeed.UpdatesMapper(options.user, removeUpdate, null);
    this.updates = ko.observableArray(updatesMapper.mapUpdates(options.updates));


    // topics filter
    this.topicsFilter = ko.observableArray(options.topicsFilter);

    this.topicsFilter.subscribe(function (val) {
        self.refreshUpdates();
    }, this);

    // post update
    this.newPostText = ko.observable("");

    this.postUpdate = ko.asyncCommand(
        function () {
            var promise = activityFeed.api.postUpdate(self.newPostText(), options.source, options.newTopics).pipe(function (result) {
                var mapper = new activityFeed.UpdatesMapper(options.user, removeUpdate, options.onUpdateViewModelInitialize);
                var update = mapper.mapUpdateToUpdateViewModel(result.value);
                self.updates.unshift(update);
                self.newPostText("");

                return update;
            });

            return promise;
        }, self.newPostText);



    // search
    this.searchTerm = ko.observable("");
    this.throttledSearchTerm = ko.computed(this.searchTerm).extend({ throttle: 400 });
    this.throttledSearchTerm.subscribe(function (val) {
        self.refreshUpdates();
    }, this);

    this.refreshUpdates = ko.asyncCommand(
        function () {
            var promise = activityFeed.api.getUpdates(options.feedType, options.customFeedTypeName, self.searchTerm(), null, options.pageSize, self.topicsFilter()).pipe(function (result) {
                self.hasMoreUpdates(!result.complete);
                self.updates(updatesMapper.mapUpdates(result.value));
            });
            return promise;
        });

    // load next page
    this.hasMoreUpdates = ko.observable(!options.isListOfUpdatesComplete);

    this.loadNextPage = ko.asyncCommand(
        function () {
            var updatesCount = self.updates().length;
            var lastUpdateDate = updatesCount > 0 ? self.updates()[updatesCount - 1].publishedOn().toISOString() : null;

            var promise = activityFeed.api.getUpdates(options.feedType, options.customFeedTypeName, self.searchTerm(), lastUpdateDate, options.pageSize, self.topicsFilter()).pipe(function (result) {
                var newUpdates = updatesMapper.mapUpdates(result.value);
                self.hasMoreUpdates(!result.complete);
                for (var i = 0, length = newUpdates.length; i < length; i++) {
                    self.updates.push(newUpdates[i]);
                }
            });
            return promise;
        }, self.hasMoreUpdates);



    // update content templates
    this.contentTemplateExists = function (update) {
        return !!options.updateContentTemplates[update.contentType()];
    };

    this.getUpdateContentTemplate = function (update) {
        var updateContentTemplate = options.updateContentTemplates[update.contentType()];
        if (updateContentTemplate == null) {
            throw "Cannot find update content template: " + updateContentTemplate;
        }
        return updateContentTemplate;
    };

    this.initialize = function () {
        if (!options.newTopics) {
            options.newTopics = null;
        }
        if (!options.customFeedTypeName) {
            options.customFeedTypeName = null;
        }

        if (options.onUpdateViewModelInitialize) {
            options.onUpdateViewModelInitialize = window[options.onUpdateViewModelInitialize];
            if (!options.onUpdateViewModelInitialize) {
                throw "Method onUpdateViewModelInitialize not found in global scope";
            }
            for (var i = 0; i < self.updates().length; i++) {
                options.onUpdateViewModelInitialize(self.updates()[i]);
            }
            updatesMapper = new activityFeed.UpdatesMapper(options.user, removeUpdate, options.onUpdateViewModelInitialize);
        }

        if (options.onInitialize) {
            window[options.onInitialize](this);
        }
    };
};